/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package cocos2d.node;

import cocos2d.common.CCPoint;
import cocos2d.common.CCRect;
import cocos2d.common.CCSize;
import cocos2d.common.schedule.CCBaseScheduler;
import cocos2d.common.schedule.CCSchedule;
import cocos2d.common.schedule.CCScheduler;
import java.util.Vector;
import javax.microedition.lcdui.Graphics;

/**
 *
 * @author KieuAnh
 */
public class CCBaseNode implements CCNode
{
    private final CCRect bound;
    private final Vector childs;
    private CCNode parent;
    private final CCPoint anchor;
    private final CCScheduler scheduler;
    private boolean isFlexibled = false;
    private boolean visibled = true;
    
    public CCBaseNode()
    {
        this.bound = new CCRect();
        this.childs = new Vector();
        this.parent = null;
        this.anchor = new CCPoint();
        this.scheduler = CCBaseScheduler.instance();  // base scheduler
    }

    // <editor-fold defaultstate="collapsed" desc="Scheduler">
    /**
     * @return the scheduler
     */
    public CCScheduler getScheduler() {
        return scheduler;
    }
    
    public void schedule(CCSchedule schedule) {
        this.getScheduler().schedule(schedule);
    }

    public void schedule(CCSchedule schedule, long time) {
        this.getScheduler().schedule(schedule, time);
    }

    public void unschedule(CCSchedule schedule) {
        this.getScheduler().unschedule(schedule);
    }

    public void run(long dt)
    {
        this.getScheduler().run(dt);
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Node">
    /**
     * @return the parent
     */
    public CCNode getParent() {
        return parent;
    }
   
    public void setParent(CCNode parent) {
        this.parent = parent;
    }
    
    /**
     * @return the children
     */
    public Vector getAllChildrens() {
        return childs;
    }
    
    public void addChild(CCNode child)
    {
        this.childs.addElement(child);
        child.setParent(this);
        
        this.updateVisibleSize();
    }
    
    public void removeChild(CCNode child)
    {
        if (this.childs.removeElement(child))
        {
            child.setParent(null);
        }
        
        this.updateVisibleSize();
    }
    
    public void removeChildrens(Vector childs)
    {
        for (int i = 0; i < childs.size(); i++) {
            Object nodeObj = childs.elementAt(i);
            if (nodeObj instanceof CCNode)
            {
                this.removeChild((CCNode) nodeObj);
            }
        }
    }
    
    public void removeAllChildrens()
    {
        for (int i = 0; i < this.childs.size(); i++) {
            Object nodeObj = this.childs.elementAt(i);
            if (nodeObj instanceof CCNode)
            {
                CCNode childNode = (CCNode) nodeObj;
                childNode.setParent(null);
            }
        }
        this.childs.removeAllElements();
    }
    
    public void removeFromParent()
    {
        if (this.parent != null)
        {
            this.parent.removeChild(this);
        }
    }
    
    public boolean isChildOf(CCNode parent)
    {
        CCNode cParent = this.parent;
        while (cParent != null && cParent != parent) {
            cParent = cParent.getParent();
        }
        
        return (cParent != null);
    }
    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc="Transform">
    /**
     * @return the position
     */
    public CCPoint getPosition() {
        return this.getBound().getPosition();
    }

    /**
     * @return the anchor
     */
    public CCPoint getAnchor() {
        return anchor;
    }
    
    public CCPoint getGlobalPosition()
    {
        return this.globalFromLocal(this.getPosition());
    }
    
    public CCPoint globalFromLocal(CCPoint local)
    {
        CCPoint global = local.copy();
        global.add(this.anchor.X.negative(), this.anchor.Y.negative());
        
        CCNode cParent = this.parent;
        while (cParent != null) {
            global.add(cParent.getPosition().X, cParent.getPosition().Y);
        }
        
        return global;
    }
    
    public CCPoint localFromGlobal(CCPoint global)
    {
        CCPoint local = global.copy();
        local.add(this.anchor.X, this.anchor.Y);
        
        CCNode cParent = this.parent;
        while (cParent != null) {
            local.add(cParent.getPosition().X.negative(), cParent.getPosition().Y.negative());
        }
        
        return local;
    }
    
    public CCSize getContentSize() {
        return this.bound.getSize();
    }
    
    public CCRect getBound()
    {
        return this.bound;
    }
    
    public CCRect getGlobalBound()
    {
        return new CCRect(this.getGlobalPosition(), this.bound.getSize());
    }
    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc="Flexible">
    private void updateVisibleSize()
    {
        if(this.isFlexibled())
        {
            CCPoint topLeft = new CCPoint(), rightBottom = new CCPoint();
            for (int i = 0; i < this.getAllChildrens().size(); i++) {
                Object nodeObj = this.getAllChildrens().elementAt(i);
                if (nodeObj instanceof CCNode)
                {
                    CCNode child = (CCNode) nodeObj;
                    topLeft.X.setRaw(Math.min(topLeft.X.getRaw(), child.getPosition().X.getRaw()));
                    topLeft.Y.setRaw(Math.min(topLeft.Y.getRaw(), child.getPosition().Y.getRaw()));
                    rightBottom.X.setRaw(Math.max(rightBottom.X.getRaw(), child.getPosition().X.add(child.getContentSize().width()).getRaw()));
                    rightBottom.Y.setRaw(Math.max(rightBottom.Y.getRaw(), child.getPosition().Y.add(child.getContentSize().height()).getRaw()));
                }
            }
            
            this.getContentSize().width().set(rightBottom.X.sub(topLeft.X));
            this.getContentSize().height().set(rightBottom.Y.sub(topLeft.Y));
        }
    }

    /**
     * @return the isFlexibled
     */
    
    public boolean isFlexibled() {
        return isFlexibled;
    }

    /**
     * @param isFlexibled the isFlexibled to set
     */
    
    public void setIsFlexibled(boolean isFlexibled) {
        if (this.isFlexibled != isFlexibled)
        {
            this.isFlexibled = isFlexibled;
            this.updateVisibleSize();
        }
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Visible">
    
    public void draw(Graphics g, long dt)
    {
        if (this.isVisibled())
        {
            for (int i = 0; i < this.childs.size(); i++) {
                Object nodeObj = this.childs.elementAt(i);

                if (nodeObj instanceof CCNode)
                {
                    CCNode child = (CCNode) nodeObj;
                    child.draw(g, dt);
                }
            }
        }
    }
    
    /**
     * @return the visible
     */
    
    public boolean isVisibled() {
        return visibled;
    }

    /**
     * @param visibled the visible to set
     */
    
    public void setVisibled(boolean visibled) {
        this.visibled = visibled;
    }
    // </editor-fold>
}